var jfJQMAmobeeAds = (function($, document, window) {
  'use strict';

  /*********** PRIVATE VARS AND FUNCTIONS *******/
  
  var ads = {},
      $document = $(document),
      $html = $('html'),
      userid = null,
      userAgent = navigator.userAgent,
      config = {
        proxyUrl: '/jfJQMAmobeeAdsPlugin/proxy.php',
        preloadJavascripts: [],
        autoLoadAds: true,
        interstitialTimeout: 7000,
        hideExistingAdsOnReload: false
      },
      platform = 'other';
  
  if (-1 !== userAgent.indexOf('iPhone')) { platform = 'iphone'; }
  else if (-1 !== userAgent.indexOf('iPad')) { platform = 'ipad'; }
  else if (-1 !== userAgent.indexOf('Android')) { platform = 'android'; }

  function getMatchingAdspaceFromAdspaces(adspaces) {
    if (typeof adspaces === 'string' || typeof adspaces === 'number') {
      return adspaces;
    }
    else if (adspaces instanceof Array) {
      return getMatchingAdspaceFromAdspaces(adspaces[0]);
    }
    else if (typeof adspaces === 'object') {
      if (typeof adspaces[platform] !== 'undefined') {
        if (adspaces[platform]) {
          return getMatchingAdspaceFromAdspaces(adspaces[platform]);
        }
        else {
          return false; //explicitly disabled for this platform
        }
      }
      else if (adspaces.standard) {
        return getMatchingAdspaceFromAdspaces(adspaces.standard);
      }
      else if (typeof adspaces.landscape !== 'undefined' && window.innerWidth > window.innerHeight) {
        return getMatchingAdspaceFromAdspaces(adspaces.landscape);
      }
      else if (typeof adspaces.portrait !== 'undefined' && window.innerWidth < window.innerHeight) {
        return getMatchingAdspaceFromAdspaces(adspaces.portrait);
      }
    }

    return false;
  }

  function getUserid() {
    var cookieName = 'jfJQMAmobeeAdsUserId';

    if (userid === null) {
      userid = getCookie(cookieName, generateUserid());
      setCookie(cookieName, userid, 60);
    }
    
    return userid;
  }
  
  function generateUserid() {
    var chars = '0123456789abcdefghiklmnopqrstuvwxyz'.split('');
    var length = 32;

    var str = '';
    for (var i = 0; i < length; i++) {
      str += chars[Math.floor(Math.random() * chars.length)];
    }
    
    return str;
  }
    
  function setCookie(key, value, expiresInDays) {
    var domainParts = window.location.host.split('.'),
        domain = domainParts[domainParts.length-2]+'.'+domainParts[domainParts.length-1],
        expiresDate = new Date();
    expiresDate.setDate(expiresDate.getDate() + expiresInDays);
    document.cookie = key + "=" + window.escape(value) + ((expiresInDays === null) ? "" : "; expires="+expiresDate.toUTCString())+"; path=/; domain="+domain;
  }

  function getCookie(key, defaultValue) {
    var i, 
        x, 
        y, 
        cookies = document.cookie.split(";");
    
    for (i=0; i < cookies.length; i++) {
      x = cookies[i].substr(0,cookies[i].indexOf("="));
      y = cookies[i].substr(cookies[i].indexOf("=")+1);
      x = x.replace(/^\s+|\s+$/g, "");
      if (x === key) {
        return window.unescape(y);
      }
    }

    return defaultValue;
  }


  function onBeforeSendAdServerRequest(e, ads, responsemarkup) {
    var $page = $(e.target);

    if (getAdServerRequestsCountForPage($page) > 0) {
      for (var idx = 0; idx < ads.length; idx++) {
        if (ads.hasOwnProperty(idx)) {
          var ad = ads[idx];
          if (ad && ad.priority <= 1) {
            ads.splice(idx, 1);
            idx--;
          }
        }
      }
    }
    
    $page.trigger('jfJQMAmobeeAds:sendAdServerRequest', [ads, responsemarkup]);
  }
  
  function onSendAdServerRequest(e, ads, responsemarkup) {
    var $page = $(e.target);
    incrementAdServerRequestsCountForPage($page);
    var adSpaces = [];
    if (ads && ads.length) {
      for (var i = 0, len = ads.length; i < len; i++) {
        var ad = ads[i];
        if (typeof ad !== 'undefined') {
          if (!ad.adspace) {
            ads.splice(i, 1);
            i--;
          }
          else if (-1 !== adSpaces.indexOf(ad.id)) {
            ads.splice(i, 1);
            i--;
          }
          else {
            adSpaces.push(ad.id);
          }
        }
      }
      
      if ($.isEmptyObject(ads)) {
        if (that.debugMode && window.console) {
          window.console.warn('No ad requests to send');
        }
        return;
      }

      
      if (that.debugMode && window.console) {
        window.console.log('sendAdServerRequest:');
        window.console.log(ads);
      }
    
      $.ajax({
        url: that.getConfig('proxyUrl'),
        type: 'POST',
        data: {
          ads: ads, 
          responsemarkup: responsemarkup,
          userid: getUserid()
        },
        dataType: 'jsonp',
        success: function(response) {
          $page.trigger('jfJQMAmobeeAds:processAdServerResponse', [{ $page: $page, adRequests: ads, data: $.parseXML(response.content) }]);
        },
        error: function(response) {
          if (that.debugMode && window.console) {
            window.console.warn('jfJQMAmobeeAds.sendAdServerRequest: bad status: '+response.status);
            window.console.warn(response);
          }
        }
      });
    }
  }
  
  function onProcessAdServerResponse (e, params) {
    var $page = params.$page,
        adRequests = params.adRequests,
        data = params.data,
        $adresponsepacket = $(data.childNodes[0]),
        $adresponses = $adresponsepacket.children(),
        $targets = $page.find('.jfJQMAmobeeAd');
        
    $adresponses.each(function(index) {
      var $response = $(this);
      var request = adRequests[index];

      if (request) {
        switch (request.type) {
          case 'interstitial':
            processAdServerResponseInterstitial($page, request, $response);
            break;
          default:
            processAdServerResponseDefault($page, request, $response);
            break;
        }
      }
    });
  }
  
  
  function processAdServerResponseDefault($page, request, $response) {
    var $target = $page.find('.jfJQMAmobeeAd[data-jfJQMAmobeeAds-adspace='+request.id+']');
    
    if ($response.find('status').text() !== '6200') {
      if (that.debugMode && window.console) {
        window.console.warn('jfJQMAmobeeAds.processAdServerResponseDefault: problem processing adpace '+request.adspace+': status required: 6200 ("Status OK"), status received: '+$response.find('status').text()+' ("'+$response.find('statusdescription').text()+'")');
      }

      if (that.getConfig('hideExistingAdsOnReload')) {
        $target.removeClass('visible').addClass('hidden');
      }
      
      if (request.adspacesFallback) {
        var fallbackRequest = $.extend({}, request);
        fallbackRequest.adspaces = fallbackRequest.adspacesFallback;
        fallbackRequest.adspacesFallback = null;
        fallbackRequest.adspace = null;
        fallbackRequest.priority = 2; //if parent ad has a low priority (<=1), fallback ads would never get processed => fake priority
        fallbackRequest = that.parseAdspaceParams(fallbackRequest);
        if (fallbackRequest.adspace) {
          that.sendAdServerRequest($page, [fallbackRequest]);
        }
      }
      
      return;
    }

    $target.attr('data-ajax', 'false');
    injectAdHtmlIntoElement(getAdHtmlForResponse($response), $target);
    $target.removeClass('hidden').addClass('visible');
  }

  function processAdServerResponseInterstitial($page, request, $response) {
    if ($response.find('status').text() !== '6200') {
      if (that.debugMode && window.console) {
        window.console.warn('jfJQMAmobeeAds.processAdServerResponseInterstitial: problem processing adpace '+request.adspace+': status required: 6200 ("Status OK"), status received: '+$response.find('status').text()+' ("'+$response.find('statusdescription').text()+'")');
      }
      return;
    }

    var adHtml = getAdHtmlForResponse($response);
    var withAutoClose = !/<!-- <connectad>yes<\/connectad> -->/.test(adHtml);

    var $interstitial = $('<div id="jfJQMAmobeeAdsInterstitial" class="jfJQMAmobeeAd" data-ajax="false"><table><tr><td id="jfJQMAmobeeAdsInterstitialContent"></td></tr></table><span class="close">X</span></div>');
    if (withAutoClose) {
      $interstitial.append($('<div class="meter"><div class="value"></div>'));
    }
    $interstitial.appendTo($('body'));

    injectAdHtmlIntoElement(adHtml, $interstitial.find('#jfJQMAmobeeAdsInterstitialContent'));

    that.showInterstitial($interstitial, withAutoClose);
  }
  
  function injectAdHtmlIntoElement(adHtml, $element) {
    $element.empty();
    if (adHtml.match(/<html/)) { //whole html document => inject iframe
      $element.html('');
      var $iframe = $('<iframe>');
      $iframe.appendTo($element);
      var iframeDoc = $iframe[0].contentDocument;
      if (iframeDoc) {
        iframeDoc.open();
        iframeDoc.writeln(adHtml);
        iframeDoc.close();
      }
    }
    else {
      adHtml = ensureExternalsScriptsLoadSynchronously(adHtml);
      $element.html(adHtml);
      $element.find('a[href]').not('[target]').attr('target', '_blank');
    }
  }
  
  function ensureExternalsScriptsLoadSynchronously(adHtml) {
    return adHtml.replace(/<script(.*)src=(["'])(https?:\/\/)(.*)(["'])/g, '<script$1src=$2/jfJQMAmobeeAds/js-proxy?url=$3$4$5');
  }
  
  function onInterstitialLinkClick(e) {
    var adspaces = $.parseJSON($(e.currentTarget).attr('data-jfJQMAmobeeAdsInterstitialAdspaces'));
    var params = { 
      type: 'interstitial',
      adspaces: adspaces
    };

    params = that.parseAdspaceParams(params);
    if (params.adspace) {
      that.sendAdServerRequest(null, [params]);
    }
  }

  function getAdHtmlForResponse($response) {
    return $response.find('responsecontent').text();
  }
  
  function getAdsForPage($page) {
    var ads = [];
    $page.find('.jfJQMAmobeeAd[data-jfJQMAmobeeAds-config]').each(function(ids, elem) {
      var params = that.parseAdspaceParams($.parseJSON($(elem).attr('data-jfJQMAmobeeAds-config')));
      if (params.adspace) {
        ads.push(params);
      }
    });

    return ads;
  }
  
  function getAdServerRequestsCountForPage($page) {
    var result = $page.attr('data-jfJQMAmobeeAds-count');
    return result ? parseInt(result, 10) : 0;
  }
  function setAdServerRequestsCountForPage($page, value) {
    return parseInt($page.attr('data-jfJQMAmobeeAds-count', value), 10);
  }
  function incrementAdServerRequestsCountForPage($page) {
    setAdServerRequestsCountForPage($page, getAdServerRequestsCountForPage($page)+1);
  }


  function init() {
    $document.
      bind('jfJQMAmobeeAds:beforeSendAdServerRequest', onBeforeSendAdServerRequest).
      bind('jfJQMAmobeeAds:sendAdServerRequest', onSendAdServerRequest).
      bind('jfJQMAmobeeAds:processAdServerResponse', onProcessAdServerResponse);

    $('[data-jfJQMAmobeeAdsInterstitialAdspaces]').live('click', onInterstitialLinkClick);
    
    if (that.getConfig('autoLoadAds')) {
      that.sendAdServerRequest();
    }
  }


  /*********** PUBLIC INTERFACE *******/
      
  var that = {

    debugMode: false,

    setConfig: function(key, value) {
      config[key] = value;
    },
    getConfig: function(key, defaultValue) {
      return typeof config[key] === 'undefined' ? defaultValue : config[key];
    },

    getUserid: getUserid,

    resetPage: function($page) {
      setAdServerRequestsCountForPage($page, 0);
    },
    
    sendAdServerRequest: function($page, ads, responsemarkup) {
      $page = $page || $('body');
      ads = ads || getAdsForPage($page);
      $page.trigger('jfJQMAmobeeAds:beforeSendAdServerRequest', [ads, responsemarkup]);
    },
    
    parseAdspaceParams: function(params) {
      params.adspace = getMatchingAdspaceFromAdspaces(params.adspaces);
      delete params.adspaces;

      return params;
    },

    showInterstitial: function($interstitial, withAutoClose) {
      var timeout;

      if (withAutoClose === undefined) {
        withAutoClose = true;
      }

      window.scrollTo(0,0);
      $html.addClass('jfJQMAmobeeAds_showInterstitial');

      if (withAutoClose) {
        var progress = 0;
        var $meterValue = $interstitial.find('.meter > .value');
        timeout = setInterval(function() {
          progress++;
          $meterValue.css('width', progress+'%');
          if (progress === 99) {
            that.hideInterstitial($interstitial, timeout, false);
          }
        }, that.getConfig('interstitialTimeout')/100);
      }

      $interstitial.on('click', 'a[href], .close', function() { that.hideInterstitial($interstitial, timeout, true); });
      $document.trigger('jfJQMAmobeeAds:showInterstitial', [{ $interstitial: $interstitial, timeout: timeout, withAutoClose: withAutoClose }]);
    },
    hideInterstitial: function($interstitial, timeout, immediately) {
      window.clearInterval(timeout);
      $html.removeClass('jfJQMAmobeeAds_interstitialTransitioned jfJQMAmobeeAds_showInterstitial');
      if (immediately) {
        $interstitial.remove();
      }
      else {
        setTimeout(function() { $interstitial.remove(); }, 1000);
      }
      $document.trigger('jfJQMAmobeeAds:hideInterstitial');
    }
  };


  
  
  $(init);
  
  return that;
  
})(jQuery, document, window);